/*
 * Glide.js
 * Ver: 1.0.4
 * Simple & efficient jQuery slider
 * Autor: @JedrzejChalubek
 * url: http://jedrzejchalubek.com
 * Licensed under the MIT license
 */

/*
 *
 * Autor Qietu.com,inc.
 * url: http://www.qietu.com
 * Autor: @qietuwang
 * 瑙ｅ喅鐘舵€佹爮锛堢偣鐐癸級鍦╥phone涓嬪鍑犱釜鐐圭偣闂 2015.10.20
 */
;(function ($, window, document, undefined) {
    var name = 'glide',
        defaults = {
            // {Int or Bool} False for turning off autoplay
            autoplay: 4000,
            /**
             * Animation time
             * !!! IMPORTANT !!!
             * That option will be use only, when css3 are not suported
             * If css3 are supported animation time is set in css declaration inside .css file
             * @type {Int}
             */
            animationTime: 500,

            /**
             * {Bool or String} Show/hide/appendTo arrows
             * True for append arrows to slider wrapper
             * False for not appending arrows
             * Id or class name (e.g. '.class-name') for appending to specific HTML markup
             */
            arrows: true,
            // {String} Arrows wrapper class
            arrowsWrapperClass: 'slider-arrows',
            // {String} Main class for both arrows
            arrowMainClass: 'slider-arrow',
            // {String} Right arrow
            arrowRightClass: 'slider-arrow--right',
            // {String} Right arrow text
            arrowRightText: 'next',
            // {String} Left arrow
            arrowLeftClass: 'slider-arrow--left',
            // {String} Left arrow text
            arrowLeftText: 'prev',

            /**
             * {Bool or String} Show/hide/appendTo bullets navigation
             * True for append arrows to slider wrapper
             * False for not appending arrows
             * Id or class name (e.g. '.class-name') for appending to specific HTML markup
             */
            nav: true,
            // {Bool} Center bullet navigation
            navCenter: true,
            // {String} Navigation class
            navClass: 'slider-nav',
            // {String} Navigation item class
            navItemClass: 'slider-nav__item',
            // {String} Current navigation item class
            navCurrentItemClass: 'slider-nav__item--current',

            // {Int or Bool} Touch settings
            touchDistance: 60,

            slideCurrentItemClass: 'slide__item--current'
        };

    /**
     * Slider Constructor
     * @param {Object} parent
     * @param {Object} options
     */
    function Glide(parent, options) {
        var _ = this;
        _.options = $.extend({}, defaults, options);

        // Sidebar
        _.parent = parent;
        // Slides Wrapper
        _.wrapper = _.parent.children();
        // Slides
        _.slides = _.wrapper.children();
        // Current slide id
        _.currentSlide = 0;
        // CSS3 Animation support
        _.CSS3support = true;

        // Initialize
        _.init();
        // Build DOM
        _.build();
        // Start autoplay
        _.play();

        /**
         * Controller
         * Touch events
         */
        if (_.options.touchDistance) {
            // Init swipe
            _.swipe();
        }

        /**
         * Controller
         * Keyboard left and right arrow keys
         */
        $(document).on('keyup', function(k) {
            // Next
            if (k.keyCode === 39) _.slide(1);
            // Prev
            if (k.keyCode === 37) _.slide(-1);
        });

        /**
         * Controller
         * Mouse over slider
         * When mouse is over slider, pause autoplay
         * On out, start autoplay again
         */
        _.parent.add(_.arrows).add(_.nav).on('mouseover mouseout', function (e) {
            // Pasue autoplay
            _.pause();
            // When mouse left slider or touch end, start autoplay anew
            if (e.type === 'mouseout') _.play();
        });

        /**
         * Controller
         * When resize browser window
         * Pause autoplay in fear of escalation
         * Reinit plugin for new slider dimensions
         * Correct crop to current slide
         * Start autoplay from beginning
         */
        $(window).on('resize', function() {
            // Reinit plugin (set new slider dimensions)
            _.init();
            // Crop to current slide
            _.slide(0);
        });

        /**
         * Returning API
         */
        return {
            current: function() {
                return -(_.currentSlide) + 1;
            },
            play: function() {
                _.play();
            },
            pause: function() {
                _.pause();
            },
            next: function(callback) {
                _.slide(1, false, callback);
            },
            prev: function(callback) {
                _.slide(-1, false, callback);
            },
            jump: function(distance, callback) {
                _.slide(distance-1, true, callback);
            },
            nav: function(target) {
                /**
                 * If navigation wrapper already exist
                 * Remove it, protection before doubled navigation
                 */
                if (_.navWrapper) {
                    _.navWrapper.remove();
                }
                _.options.nav = (target) ? target : _.options.nav;
                // Build
                _.navigation();
            },
            arrows: function(target) {
                /**
                 * If arrows wrapper already exist
                 * Remove it, protection before doubled arrows
                 */
                if (_.arrowsWrapper) {
                    _.arrowsWrapper.remove();
                }
                _.options.arrows = (target) ? target : _.options.arrows;
                // Build
                _.arrows();
            }
        };
    }

    /**
     * Building slider DOM
     */
    Glide.prototype.build = function() {
        var _ = this;

        /**
         * Arrows
         * If option is true and there is more than one slide
         * Append left and right arrow
         */
        if (_.options.arrows) _.arrows();

        /**
         * Navigation
         * If option is true and there is more than one slide
         * Append navigation item for each slide
         */
        if (_.options.nav) _.navigation();
    };

    /**
     * Building navigation DOM
     */
    Glide.prototype.navigation = function() {
        var _ = this;

        if (_.slides.length > 1) {
            // Cache
            var o = _.options,
                /**
                 * Setting append target
                 * If option is true set default target, that is slider wrapper
                 * Else get target set in options
                 * @type {Bool or String}
                 */
                target = (_.options.nav === true) ? _.parent : _.options.nav;

            // Navigation wrapper
            _.navWrapper = $('<ul />', {
                'class': o.navClass
            }).appendTo(target);

            // Cache
            var nav = _.navWrapper,
                item;

            // Generate navigation items
            for (var i = 0; i < _.slides.length; i++) {
                item = $('<li class="'+ o.navItemClass +'" data-distance="'+ i +'">').appendTo(nav);

                nav[i+1] = item;
            }

            // Cache
            var navChildren = nav.children();

            // Add navCurrentItemClass to the first navigation item
            navChildren.eq(0).addClass(o.navCurrentItemClass);

            // Qietu.com addons  start
            _.slides.eq(0).addClass(o.slideCurrentItemClass);
            //Qietu.com addons end


            // If centered option is true
            if (o.navCenter) {
                // Center bullet navigation
                nav.css({
                    'left': '50%',
                    'width': navChildren.outerWidth(true) * navChildren.length,
                    'margin-left': -nav.outerWidth(true)/2
                });
            }

            /**
             * Controller
             * On click in arrows or navigation, get direction and distance
             * Then slide specified distance
             */
            navChildren.on('click touchstart', function(e) {
                // prevent normal behaviour
                e.preventDefault();
                // Slide distance specified in data attribute
                _.slide( $(this).data('distance'), true );
            });
        }
    };

    /**
     * Building arrows DOM
     */
    Glide.prototype.arrows = function() {
        var _ = this;

        if (_.slides.length > 1) {
            var o = _.options,
                /**
                 * Setting append target
                 * If option is true set default target, that is slider wrapper
                 * Else get target set in options
                 * @type {Bool or String}
                 */
                target = (_.options.arrows === true) ? _.parent : _.options.arrows;

            // Arrows wrapper
            _.arrowsWrapper = $('<div />', {
                'class': o.arrowsWrapperClass
            }).appendTo(target);

            // Cache
            var arrows = _.arrowsWrapper;

            // Right arrow
            arrows.right = $('<a />', {
                'href': '#',
                'class': o.arrowMainClass + ' ' + o.arrowRightClass,
                // Direction and distance -> One forward
                'data-distance': '1',
                'html': o.arrowRightText
            }).appendTo(arrows);

            // Left arrow
            arrows.left = $('<a />', {
                'href': '#',
                'class': o.arrowMainClass + ' ' + o.arrowLeftClass,
                // Direction and distance -> One backward
                'data-distance': '-1',
                'html': o.arrowLeftText
            }).appendTo(arrows);

            /**
             * Controller
             * On click in arrows or navigation, get direction and distance
             * Then slide specified distance
             */
            arrows.children().on('click touchstart', function(e) {
                // prevent normal behaviour
                e.preventDefault();
                // Slide distance specified in data attribute
                _.slide( $(this).data('distance'), false );
            });
        }
    };


    /**
     * Slides change & animate logic
     * @param  {int} distance
     * @param  {bool} jump
     * @param  {function} callback
     */
    Glide.prototype.slide = function(distance, jump, callback) {
        // Cache elements
        var _ = this,
            currentSlide = (jump) ? 0 : _.currentSlide,
            slidesLength = -(_.slides.length-1),
            navCurrentClass = _.options.navCurrentItemClass,
            slidesSpread = _.slides.spread;

        /*Qietu.com*/
        slideCurrentClass = _.options.slideCurrentItemClass,

        /**
         * Stop autoplay
         * Clearing timer
         */
            _.pause();

        /**
         * Check if current slide is first and direction is previous, then go to last slide
         * or current slide is last and direction is next, then go to the first slide
         * else change current slide normally
         */
        if ( currentSlide === 0 && distance === -1 ) {
            currentSlide = slidesLength;
        } else if ( currentSlide === slidesLength && distance === 1 ) {
            currentSlide = 0;
        } else {
            currentSlide = currentSlide + (-distance);
        }

        /**
         * Crop to current slide.
         * Mul slide width by current slide number.
         */
        var translate = slidesSpread * currentSlide + 'px';

        // While CSS3 is supported
        if (_.CSS3support) {
            // Croping by increasing/decreasing slider wrapper translate
            _.wrapper.css({
                '-webkit-transform': 'translate3d('+ translate +', 0px, 0px)',
                '-moz-transform': 'translate3d('+ translate +', 0px, 0px)',
                '-ms-transform': 'translate3d('+ translate +', 0px, 0px)',
                '-o-transform': 'translate3d('+ translate +', 0px, 0px)',
                'transform': 'translate3d('+ translate +', 0px, 0px)'
            });
            // Else use $.animate()
        } else {
            // Croping by increasing/decreasing slider wrapper margin
            _.wrapper.stop().animate({ 'margin-left': translate }, _.options.animationTime);
        }

        // Set to navigation item current class
        if (_.options.nav) {
            _.navWrapper.children()
                .eq(-currentSlide)
                .addClass(navCurrentClass)
                .siblings()
                .removeClass(navCurrentClass);
        }

        // Update current slide globaly
        _.currentSlide = currentSlide;

        // Qietu.com addons  start
        _.slides.eq(-currentSlide).addClass(slideCurrentClass).siblings().removeClass(slideCurrentClass);
        //Qietu.com addons end

        // Callback
        if ( (callback !== 'undefined') && (typeof callback === 'function') ) callback();

        /**
         * Start autoplay
         * After slide
         */
        _.play();
    };

    /**
     * Autoplay logic
     * Setup counting
     */
    Glide.prototype.play = function() {
        var _ = this;

        if (_.options.autoplay) {
            _.auto = setInterval(function() {
                _.slide(1, false);
            }, _.options.autoplay);
        }
    };

    /**
     * Autoplay pause
     * Clear counting
     */
    Glide.prototype.pause = function() {
        if (this.options.autoplay) {
            this.auto = clearInterval(this.auto);
        }
    };

    /**
     * Change sildes on swipe event
     */
    Glide.prototype.swipe = function() {
        // Cache
        var _ = this,
            touch,
            touchDistance,
            touchStartX,
            touchStartY,
            touchEndX,
            touchEndY,
            touchHypotenuse,
            touchCathetus,
            touchSin,
            MathPI = 180 / Math.PI,
            subExSx,
            subEySy,
            powEX,
            powEY;

        /**
         * Touch start
         * @param  {Object} e event
         */
        _.parent.on('touchstart', function(e) {
            // Cache event
            touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];

            // Get touch start points
            touchStartX = touch.pageX;
            touchStartY = touch.pageY;
        });

        /**
         * Touch move
         * From swipe length segments calculate swipe angle
         * @param  {Obejct} e event
         */
        _.parent.on('touchmove', function(e) {
            // Cache event
            touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];

            // Get touch end points
            touchEndX = touch.pageX;
            touchEndY = touch.pageY;

            // Calculate start, end points
            subExSx = touchEndX - touchStartX;
            subEySy = touchEndY - touchStartY;
            // Bitwise subExSx pow
            powEX = Math.abs( subExSx << 2 );
            // Bitwise subEySy pow
            powEY = Math.abs( subEySy << 2 );

            // Calculate the length of the hypotenuse segment
            touchHypotenuse = Math.sqrt( powEX + powEY );
            // Calculate the length of the cathetus segment
            touchCathetus = Math.sqrt( powEY );
            // Calculate the sine of the angle
            touchSin = Math.asin( touchCathetus/touchHypotenuse );

            // While touch angle is lower than 32 degrees, block vertical scroll
            if( (touchSin * MathPI) < 32 ) e.preventDefault();
        });

        /**
         * Touch end
         * @param  {Object} e event
         */
        _.parent.on('touchend', function(e) {
            // Cache event
            touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];

            // Calculate touch distance
            touchDistance = touch.pageX - touchStartX;

            // While touch is positive and greater than distance set in options
            if ( touchDistance > _.options.touchDistance ) {
                // Slide one backward
                _.slide(-1);
                // While touch is negative and lower than negative distance set in options
            } else if ( touchDistance < -_.options.touchDistance) {
                // Slide one forward
                _.slide(1);
            }
        });
    };

    /**
     * Initialize
     * Get & set dimensions
     * Set animation type
     */
    Glide.prototype.init = function() {
        var _ = this,
        // Get sidebar width
            sliderWidth = _.parent.width();
        // Get slide width
        _.slides.spread = sliderWidth;

        // Set wrapper width
        _.wrapper.width(sliderWidth * _.slides.length);
        // Set slide width
        _.slides.width(_.slides.spread);

        // If CSS3 Transition isn't supported switch CSS3support variable to false and use $.animate()
        if ( !isCssSupported("transition") || !isCssSupported("transform") ) _.CSS3support = false;
    };

    /**
     * Function to check css3 support
     * @param  {String}  declaration name
     * @return {Boolean}
     */
    function isCssSupported(declaration) {
        var supported = false,
            prefixes = 'Khtml ms O Moz Webkit'.split(' '),
            clone = document.createElement('div'),
            declarationCapital = null;

        declaration = declaration.toLowerCase();
        if (clone.style[declaration] !== undefined) supported = true;
        if (supported === false) {
            declarationCapital = declaration.charAt(0).toUpperCase() + declaration.substr(1);
            for( var i = 0; i < prefixes.length; i++ ) {
                if( clone.style[prefixes[i] + declarationCapital ] !== undefined ) {
                    supported = true;
                    break;
                }
            }
        }

        if (window.opera) {
            if (window.opera.version() < 13) supported = false;
        }

        return supported;
    }

    $.fn[name] = function (options) {
        return this.each(function () {
            if ( !$.data(this, 'api_' + name) ) {
                $.data(this, 'api_' + name,
                    new Glide($(this), options)
                );
            }
        });
    };

})(jQuery, window, document);